#pragma once

#include <iostream>
namespace lcir {
template <class NodeTy, bool isReverse, bool isConst>
class IListIterator;
template <class NodeTy>
class ListNodeBase {
  ListNodeBase *prev{nullptr};
  ListNodeBase *next{nullptr};
  // 标记该节点是否为End节点
  bool isEnd{false};

 public:
  virtual ~ListNodeBase() {}
  ListNodeBase() = default;
  ListNodeBase(bool isEnd) : isEnd(isEnd){};

  using type = NodeTy;
  friend class IListIterator<NodeTy, true, true>;
  friend class IListIterator<NodeTy, true, false>;
  friend class IListIterator<NodeTy, false, true>;
  friend class IListIterator<NodeTy, false, false>;

  // friend class IListIterator;
  const ListNodeBase *getPrev() const { return prev; }
  ListNodeBase *getPrev() { return prev; }
  const ListNodeBase *getNext() const { return next; }
  ListNodeBase *getNext() { return next; }
  void setPrev(ListNodeBase *node) { prev = node; }
  void setNext(ListNodeBase *node) { next = node; }
  // 判断一个节点是否已经被插入
  bool inserted() { return prev || next; }

  /**
   * @param 返回当前节点是否是链表尾节点
   */
  bool isEndNode() const { return isEnd; }
};

/// 链表尾节点(end)
template <class NodeTy>
class EndNode : public ListNodeBase<NodeTy> {
 public:
  EndNode() : ListNodeBase<NodeTy>(true) {
    this->setNext(this);
    this->setPrev(this);
  }
  void reset() {
    this->setNext(this);
    this->setPrev(this);
  }
  bool empty() const {
    return this == this->getPrev();
  }
};

template <class NodeTy>
class IListNode : public ListNodeBase<NodeTy> {
 public:
  using type = typename ListNodeBase<NodeTy>::type;
  NodeTy *getNext() { return static_cast<NodeTy *>(ListNodeBase<NodeTy>::getNext()); }
  NodeTy *getPrev() { return static_cast<NodeTy *>(ListNodeBase<NodeTy>::getPrev()); }
  void setPrev(NodeTy *node) { ListNodeBase<NodeTy>::setPrev(node); }
  void setNext(NodeTy *node) { ListNodeBase<NodeTy>::setNext(node); }
};

// template <class NodeTy> class ListNodeBase;

// template<class ChildTy, class ParentTy>
// concept NestNodeConcept = requires(ChildTy c, ParentTy p){
//   c.getParent();
//   p.getSubList();
// };
/// NodeTy类型需要提供getParent()方法
/// ParentTy需要提供静态方法getSubList()返回一个成员引用
/// 这里不方便用concept就不用了
template <class NodeTy, class ParentTy>
class NestListNode : public IListNode<NodeTy> {
 private:
  // 如果NodeTy不提供getParent方法，编译期报错，这里就不搞concept了
  ParentTy *getParentNode() { return static_cast<NodeTy *>(this)->getParent(); }

 public:
  using nodeType = NodeTy;
  using parentType = ParentTy;

  /// 返回下一个节点指针，或nullptr
  NodeTy *getNextNode() {
    const auto &list = getParentNode()->getSubList();
    return list.getNext(static_cast<NodeTy *>(this));
  }

  NodeTy *getPrevNode() {
    const auto &list = getParentNode()->getSubList();
    return list.getNext(static_cast<NodeTy *>(this));
  }

  // 这个删除后自动释放内存
  void eraseFromParent() {
    auto &list = getParentNode()->getSubList();
    list.erase(static_cast<NodeTy *>(this));
  }

  // 这个不会释放内存
  void removeFromParent() {
    auto &list = getParentNode()->getSubList();
    list.remove(static_cast<NodeTy *>(this));
  }

  // TODO insert方法
  // insert时候应该设置parent节点
  // insert(parent, front, this)
};

namespace listnode::detail {
/// 类型萃取器
template <class NodeTy, bool isConst>
struct Trait;

template <class NodeTy>
struct Trait<NodeTy, true> {
  using pointer = const NodeTy *;
  using reference = const NodeTy &;
  using nodePointer = const ListNodeBase<NodeTy> *;
  using nodeReference = const ListNodeBase<NodeTy> &;
};

template <class NodeTy>
struct Trait<NodeTy, false> {
  using pointer = NodeTy *;
  using reference = NodeTy &;
  using nodePointer = ListNodeBase<NodeTy> *;
  using nodeReference = ListNodeBase<NodeTy> &;
};

/// listnode的私有访问器
template <class NodeTy, bool isConst>
class Accessor {
  using trait = Trait<NodeTy, isConst>;
  using pointer = typename trait::pointer;
  using reference = typename trait::reference;

 public:
  static pointer getNodePtr(NodeTy *ty) { return ty; }
  static reference getNodeRef(NodeTy *ty) { return ty; }
};

}  // namespace listnode::detail
/**
 * @brief 小帮手函数，给listnode设置边
 */
template <class NodeTy>
inline void setEdge(NodeTy *prev, NodeTy *next) {
  static_cast<IListNode<NodeTy> *>(prev)->setNext(next);
  static_cast<IListNode<NodeTy> *>(next)->setPrev(prev);
}
};  // namespace lcir